Skip to content

Rework the MathJax.typesetPromise usage.#1431

Merged
Alex-Jordan merged 3 commits into
openwebwork:PG-2.21from
drgrice1:mathjax-typeset-promise-rework
Jun 9, 2026
Merged

Rework the MathJax.typesetPromise usage.#1431
Alex-Jordan merged 3 commits into
openwebwork:PG-2.21from
drgrice1:mathjax-typeset-promise-rework

Conversation

@drgrice1

@drgrice1 drgrice1 commented Jun 7, 2026

Copy link
Copy Markdown
Member

The MathJax.typesetPromise calls no longer need to be passed through the MathJax.startupPromise according to @dpvc. See his comments on this in openwebwork/webwork2#2955.

Also, make the MathJax.typesetPromise calls to typeset popover contents specific to the particular popover that needs to be typeset instead of typesetting all popovers in the page. This is not done in the way that @dpvc suggested because moving the typesetting from the show.bs.popover event to the shown.bs.popover event results in visual motion as the popover is typeset and possibly resized, and that is not desirable. Instead a timeout is used. This works because Bootstrap creates the popover.tip element immediately after Bootstrap triggers the show.bs.popover event, and so when the timeout handler is executed it is available to work with. But that is still before the css transitions are complete which is when the shown.bs.popover event is triggered.

Note that in htdocs/js/Knowls/knowl.js and htdocs/js/DragNDrop/dragndrop.js, the typesetPromise method is often not yet defined on the MathJax object when those calls are made. That is okay, because if it isn't yet defined, that means that MathJax is still typesetting the page, and gets those elements. Generally the call is only needed for cases where those things are added to the page later.

@Alex-Jordan Alex-Jordan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing any issues from using this branch. I'm not sure what to look at for testing. But I'll mark it as approved.

@dpvc

dpvc commented Jun 7, 2026

Copy link
Copy Markdown
Member

I still think that using the show.bs.popover to initiate the MathJax typesetting is the wrong place for this, and that you are working harder than necessary to overcome the fact that this is the wrong event to use for this. It relies on subtle timing issues: the fact that the popover isn't currently in the DOM, but MathJax's typesetting is in a promise, and so it not done until the next javascript idle time, with the expectation that the popover will be in place by the time MathJax runs. That seems fragile to me.

Instead, I'd suggest using the inserted.bs.popover event rather than show.bs.popover, since that seems to be exactly what you are looking for (the popover is in the DOM but not yet revealed). Then popover.tip will be available and you don't need all the fragile setTimeout() commands.

Then in feedback.js, you can combine the current show.bs.popover and shown.bs.popover to a single inserted.bs.popover event handler.

If you really want to avoid jitter from MathJax's typesetting of expressions, not just in popovers, but in the page itself, you could add

document.querySelector('#problem_body').style.visibility="hidden";

to the bottom of the mathjax-config.js file, and insert

      pageReady() {
        return MathJax.startup.defaultPageReady()
          .then(() => document.querySelector('#problem_body').style.visibility='');
      },

into the startup block of the configuration. This will hide the problem until after MathJax has typeset all the expressions.

drgrice1 added 2 commits June 7, 2026 05:56
The `MathJax.typesetPromise` calls no longer need to be passed through
the `MathJax.startupPromise` according to @dpvc. See his comments on
this in openwebwork/webwork2#2955.

Also, make the `MathJax.typesetPromise` calls to typeset popover
contents specific to the particular popover that needs to be typeset
instead of typesetting all popovers in the page. This is not done in the
way that @dpvc suggested because moving the typesetting from the
`show.bs.popover` event to the `shown.bs.popover` event results in
visual motion as the popover is typeset and possibly resized, and that
is not desirable. Instead a timeout is used.  This works because
Bootstrap creates the `popover.tip` element immediately after Bootstrap
triggers the `show.bs.popover` event, and so when the timeout handler is
executed it is available to work with. But that is still before the css
transitions are complete which is when the `shown.bs.popover` event is
triggered.

Note that in `htdocs/js/Knowls/knowl.js` and `htdocs/js/DragNDrop/dragndrop.js`,
the `typesetPromise` method is often not yet defined on the `MathJax`
object when those calls are made.  That is okay, because if it isn't yet
defined, that means that MathJax is still typesetting the page, and gets
those elements.  Generally the call is only needed for cases where those
things are added to the page later.
…event.

This is certainly better than a timeout, and I don't know how I missed
that event. To be honest I didn't know it existed and have missed it in
the documentation for years. Thanks @dpvc for pointing this out.
@drgrice1 drgrice1 force-pushed the mathjax-typeset-promise-rework branch from f2bae2e to 52c8539 Compare June 7, 2026 11:12
@drgrice1

drgrice1 commented Jun 7, 2026

Copy link
Copy Markdown
Member Author

I switched to the the inserted.bs.popover event. Thanks for pointing that out @dpvc. I didn't even know that event existed, and have missed that in the documentation for years. It certainly is the correct event, and is better than a timeout.

@dpvc dpvc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, with one question about an update that might not be needed.

Comment thread htdocs/js/Feedback/feedback.js Outdated
}
feedbackBtn.addEventListener('inserted.bs.popover', () => {
// Render MathJax previews.
if (window.MathJax) MathJax.typesetPromise([feedbackPopover.tip]).then(() => feedbackPopover.update());

@dpvc dpvc Jun 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested it, but I wonder if the popover update is still needed, as it hasn't been shown, yet, and showing it may get the position/size right automatically. Just a thought.

@dpvc

dpvc commented Jun 7, 2026

Copy link
Copy Markdown
Member

I didn't even know that event existed, and have missed that in the documentation for years.

I didn't know about it, either, but hoped there might be one for "created but not yet shown", and so looked for the list of events, and there it was!

@drgrice1

drgrice1 commented Jun 7, 2026

Copy link
Copy Markdown
Member Author

Yeah, I might have missed it partially due to the order they list the events in the documentation. The inserted event is listed before both the show and shown events. Yeah, I am just making excuses for not reading carefully, but it might have helped if they were listed in the order they are triggered.

@drgrice1

drgrice1 commented Jun 7, 2026

Copy link
Copy Markdown
Member Author

I will check on if the feedbackPopover.update is still needed or not.

@dpvc

dpvc commented Jun 7, 2026

Copy link
Copy Markdown
Member

it might have helped if they were listed in the order they are triggered.

Agreed. That would make things clearer.

I am seeing several instances where the function is not defined.  So
protect against calling it if it isn't.  Presumably the cases where it
is not defined will still be caught by the initial typeset.
@drgrice1

drgrice1 commented Jun 7, 2026

Copy link
Copy Markdown
Member Author

I added protection against calling the typesetPromise method when it is not defined in all cases. There were several instances where I was still seeing that it was not.

Also, it seems that the feedbackPopover.update() call is still needed. I still see cases where the popover does not get resized correctly if it is removed.

@dpvc

dpvc commented Jun 7, 2026

Copy link
Copy Markdown
Member

OK, sounds good. Thanks for checking!

drgrice1 added a commit to drgrice1/webwork2 that referenced this pull request Jun 7, 2026
This was suggested by @dpvc in
openwebwork/pg#1431.  The point is to prevent
the visual motion that occurs while the MathJax content is rendered.
This doesn't use the `#problem_body` id selector since that is not on
all problems (it isn't in Gateway tests), but uses the
`.problem-content` class selector instead, since that is on all
problems.  Also, a `for of` loop and `document.querySelectorAll` is
needed for tests, since there can be more than one problem.

I am not entirely sold on the empty area shown in the mean time, but it
does prevent the jitter for the text within the problem. Perhaps if
someone wants to toy with css, a loading block could be shown with a
transition that fades in the problem when the MathJax rendering is
completed.

Note that webwork2 renders MathJax in places outside of the problem
content, and those will not be affected by this.

@somiaj somiaj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A quick test of various rendering, popups, and everything worked. There are multiple approvals, but some changes since the last one, I'm going to merge soon so it can get more testing.

@Alex-Jordan Alex-Jordan merged commit 4762398 into openwebwork:PG-2.21 Jun 9, 2026
3 checks passed
drgrice1 added a commit to drgrice1/webwork2 that referenced this pull request Jun 9, 2026
This was suggested by @dpvc in
openwebwork/pg#1431.  The point is to prevent
the visual motion that occurs while the MathJax content is rendered.
This doesn't use the `#problem_body` id selector since that is not on
all problems (it isn't in Gateway tests), but uses the
`.problem-content` class selector instead, since that is on all
problems.  Also, a `for of` loop and `document.querySelectorAll` is
needed for tests, since there can be more than one problem.

I am not entirely sold on the empty area shown in the mean time, but it
does prevent the jitter for the text within the problem. Perhaps if
someone wants to toy with css, a loading block could be shown with a
transition that fades in the problem when the MathJax rendering is
completed.

Note that webwork2 renders MathJax in places outside of the problem
content, and those will not be affected by this.
@drgrice1 drgrice1 deleted the mathjax-typeset-promise-rework branch June 9, 2026 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants